﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Syngine.Components.Animations;

namespace Syngine.Components.ParticleSystems
{
	/// <summary>
	/// 
	/// </summary>
	public class ParticleSystem : Drawable, IPlayable
	{
		private readonly List<Particle> _particles = new List<Particle>();
		private int _spawnedPerSecondCount;

		/// <summary>
		/// Initializes a new instance of the <see cref="ParticleSystem"/> class.
		/// </summary>
		/// <param name="spawnsPerSecond">The spawns per second.</param>
		public ParticleSystem(float spawnsPerSecond) : this(spawnsPerSecond, float.MaxValue)
		{
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="ParticleSystem"/> class.
		/// </summary>
		/// <param name="spawnsPerSecond">The spawns per second.</param>
		/// <param name="lifeTime">The life time.</param>
		public ParticleSystem(float spawnsPerSecond, float lifeTime)
		{
			SpawnsPerSecond = spawnsPerSecond;
			LifeTime = lifeTime;
		}

		/// <summary>
		/// 
		/// </summary>
		public float LifeTime { get; set; }

		/// <summary>
		/// 
		/// </summary>
		public ParticleEmitter Emitter { get; set; }

		/// <summary>
		/// Determines how many particles will spawn per second.
		/// </summary>
		public float SpawnsPerSecond { get; set; }

		/// <summary>
		/// 
		/// </summary>
		private float SecondTimer { get; set; }

		/// <summary>
		/// 
		/// </summary>
		private float LifeTimer { get; set; }

		/// <summary>
		/// 
		/// </summary>
		public override void Initialize()
		{
			if (Emitter == null)
			{
				var viewPort = GameContext.Game.GraphicsDevice.Viewport;
				Emitter = new ParticleEmitter(new Rectangle(viewPort.Width / 2, viewPort.Height / 2, 50, 1), new Vector2(-50, -100), new Vector2(50, -100));
			}

			base.Initialize();
		}

		/// <summary>
		/// 
		/// </summary>
		public PlayableState State { get; private set; }

		/// <summary>
		/// 
		/// </summary>
		public virtual void Play()
		{
			State = PlayableState.Playing;
		}

		/// <summary>
		/// 
		/// </summary>
		public virtual void Stop()
		{
			LifeTimer = 0;
			SecondTimer = 0;
			_particles.Clear();
			_spawnedPerSecondCount = 0;
			State = PlayableState.Stopped;
		}

		/// <summary>
		/// 
		/// </summary>
		public virtual void Pause()
		{
			State = (State == PlayableState.Playing) ? PlayableState.Paused : PlayableState.Playing;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="context"></param>
		public override void LoadContent(LoadContext context)
		{
		}

		/// <summary>
		/// 
		/// </summary>
		public override void UnloadContent()
		{
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="context"></param>
		protected override void DrawCore(DrawContext context)
		{
			for (int i = 0; i < _particles.Count; i++)
			{
				_particles[i].Draw(context);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="context"></param>
		protected override void UpdateCore(UpdateContext context)
		{
			if (State == PlayableState.Playing)
			{
				var elapsedTime = (float)context.GameTime.ElapsedGameTime.TotalSeconds;
				LifeTimer += elapsedTime;
				SecondTimer += elapsedTime;

				if (LifeTimer >= LifeTime)
				{
					Stop();
					return;
				}

				if (SecondTimer > 1.0f)
				{
					SecondTimer -= 1.0f;
					_spawnedPerSecondCount = 0;
				}

				var particlesToSpawn = Math.Floor((SpawnsPerSecond * SecondTimer) - _spawnedPerSecondCount);

				EmitParticles(particlesToSpawn);

				_spawnedPerSecondCount += (int)particlesToSpawn;

				UpdateParticles(context);
			}
		}

		private void UpdateParticles(UpdateContext context)
		{
			for (var i = 0; i < _particles.Count; i++)
			{
				if (_particles[i].IsDead)
				{
					_particles.RemoveAt(i--);
					continue;
				}

				_particles[i].Update(context);
			}
		}

		private void EmitParticles(double particlesToSpawn)
		{
			for (var i = 0; i < particlesToSpawn; i++)
			{
				// loop through how many particles should be spawned.
				var particle = new Particle
				{
					Acceleration = new Vector2(0.0f),
					Mass = 0.0f,
					Velocity = new Vector2(1.035f),
					StartAlpha = 100f,
					LifeTime = 5f
				};

				_particles.Add(particle);

				Emitter.Emit(particle);
			}
		}
	}
}